# -*-coding:Utf-8 -* 
""" Level loader module
"""
import bge, bgl, blf, mathutils, aud, os, pickle
from . import SZ_Globals,setState, IN,UI, core

class Level(object):
	_singletone = None
	
	globalLib = {}
	
	class level_loading_event(core.BasicEvent):
		layerDefault = 'lvl'
		
		def __init__(self):
			core.BasicEvent.__init__(self)
			self.layer = Level.level_loading_event.layerDefault
			self.loading = 0.0
			self.callbacks_progress = 0
			SZ_Globals['loading'][1].level = self.loading
			self.name = None
		
		def update(self):
			if -1.0 > self.loading:
				return
			if self.loading < -0.6:
				self.endCallback(Level._singletone)
				#print("Gru -0.6")
			elif self.loading < -0.5:
				self.exitMap(Level._singletone)
				#print("Gru -0.5")
			elif self.loading < -0.4:
				self.loading = -0.35
				#print("Gru -0.4")
			elif self.loading < -0.3:
				self.waitLvlRestart(Level._singletone)
				#print("Gru -0.3")
			if self.loading < 0.0:
				return
			if self.loading < 0.4:
				self.loadLib(Level._singletone)
				#print("Gru 0.4")
			elif self.loading < 0.8:
				self.loadMap(Level._singletone)
				#print("Gru 0.8")
			elif self.loading < 1.0:
				self.initMap(Level._singletone)
				#print("Gru 1.0")
				
			
		def endCallback(self,lvl):
			if self.callbacks_progress >= len(lvl._ending_callbacks):
				self.loading = -0.55
				self.callbacks_progress = 0
				return
			func = lvl._ending_callbacks[self.callbacks_progress]
			self.callbacks_progress += 1
			if func(self,lvl):
				lvl._ending_callbacks.remove(func)
				self.callbacks_progress -= 1
				return
				
		def exitMap(self,lvl):
			self.stop()
			self.layer = 0
			self.activate()
			SZ_Globals['lvl_mEvent'].freeAllEvents()
			if lvl.libraries != {} and type(lvl.libraries) == dict:
				lvl.libraries = tuple(lvl.libraries.values())
			for name in bge.logic.LibList():
				print(name)
				if name in lvl.maps or name in lvl.libraries:
					bge.logic.LibFree(name)
			SZ_Globals['LvlScene'].restart()
			SZ_Globals['LvlScene'] == None
			self.loading = -0.45
		
		def waitLvlRestart(self,lvl):
			for scene in bge.logic.getSceneList():
					if scene.name == 'main':
						SZ_Globals['LvlScene'] = scene
						self.stop()
						if self.name != None:
							self.loading = 0.0
							self.layer = 'lvl'
							self.activate()
						else:
							self.loading = -0.1
		
		def loadLib(self,lvl):
			SZ_Globals['loading'][1].level = self.loading
			if self.loading <= .0:
				lvl.setCurrentLevel(self.name)
				self.loading = 0.05
				self.libLoading = iter(lvl.libraries)
				self.libResult = {}
				self.libProgress = 1
			elif self.loading < 0.4:
				k = next(self.libLoading,False)
				if not k:
					lvl.libraries = self.libResult
					del self.libResult
					del self.libLoading
					del self.libProgress
					self.loading = 0.4
					return
				if  lvl.libraries[k][1] == "Scene":
					ret = bge.logic.LibLoad(lvl.libraries[k][0],lvl.libraries[k][1],load_actions=False)
				else:
					ret = bge.logic.LibLoad(lvl.libraries[k][0],lvl.libraries[k][1])
				print(ret.libraryName,ret.timeTaken)
				self.libResult[k] = lvl.libraries[k][0]
				self.loading = 0.05 + (self.libProgress/len(lvl.libraries))*0.34
				self.libProgress += 1
			return
			
		def finishBlendLoading(self,status):
			self.loading = .80
			
		def loadMap(self,lvl):
			SZ_Globals['loading'][1].level = self.loading
			if self.loading <= .4:
				self.blendloading = bge.logic.LibLoad(lvl.maps[lvl.mapIndex],"Scene",load_actions=True,async=True)
				self.blendloading.onFinish = self.finishBlendLoading
				self.loading = 0.401
			else:
				self.loading = 0.401+(self.blendloading.progress*0.398)
			return 
			
		def initMap(self,lvl):
			if self.callbacks_progress >= len(lvl._starting_callbacks):
				self.stop()
				setState("InGame")
				return
			self.loading = 0.8+((self.callbacks_progress/len(lvl._starting_callbacks))*0.2)
			SZ_Globals['loading'][1].level = self.loading
			func = lvl._starting_callbacks[self.callbacks_progress]
			self.callbacks_progress += 1
			if func(self,lvl):
				lvl._starting_callbacks.remove(func)
				self.callbacks_progress -= 1
			
	
	@classmethod
	def show_loadingScreen(cls,pre = None,post = None):
		SZ_Globals['2DScreen'].setLayer('loading')
	@classmethod
	def hide_loadingScreen(cls,pre = None,post = None):
		SZ_Globals['2DScreen'].setLayer()
	
	@classmethod
	def addStartingCallback(cls,func):
		if callable(func):
			cls._singletone._starting_callbacks.append(func)
	
	@classmethod
	def addEndingCallback(cls,func):
		if callable(func):
			cls._singletone._ending_callbacks.append(func)
	
	@classmethod
	def load(cls, name):
		self = cls._singletone
		if name not in self.levels or name == self.current:
			return False
		setState('LoadingScreen')
		if SZ_Globals['LvlScene'].suspended:
			SZ_Globals['LvlScene'].resume()
		evt = self.exitMap()
		if evt == None:
			evt = cls.level_loading_event()
			evt.activate()
		evt.name = name
		print('starting load')
		
	@classmethod
	def nextMap(cls):
		self = cls._singletone
		idx = self.mapIndex+1
		if idx >= len(self.maps):
			return
		bge.logic.LibFree(self.maps[self.mapIndex])
		self.mapIndex = idx
	
	@classmethod
	def MapsList(cls):
		return cls._singletone.getMapsList()
	
	def __new__(cls, *args):
		if cls._singletone == None:
			cls._singletone = object.__new__(cls)
			cls._singletone._init  = False
		return cls._singletone
		
	def __init__(self):
		if self._init:
			return
		self.levels = {}
		self._starting_callbacks = []
		self._ending_callbacks = []
		self.current = None
		self.mapIndex = 0
		self.maps = []
		self.libraries = []
		self.settings = {}
		self.stats = {}
		self._init = True
		
	def exitMap(self,callback = None):
		if self.current == None:
			return
		print('clean grumi')
		evt = Level.level_loading_event()
		#evt.layer = 'lvl'
		evt.loading = -1.0
		evt.after_exit_callback = None
		if callable(callback):
			evt.after_exit_callback = callback
		evt.activate()
		return evt
		
	def setCurrentLevel(self,value):
		if value not in self.levels:
			return False
		with open(bge.logic.expandPath(self.levels[value]),'rb') as mapFile:
			self.maps = pickle.load(mapFile)
			self.libraries = Level.globalLib.copy()
			self.libraries.update(pickle.load(mapFile))
			self.settings = pickle.load(mapFile)
			self.stats = {}
			self.current = value
			
	def getMapsList(self):
		return tuple(self.levels.keys())
	
SZ_Globals["state_func"]['LoadingScreen'] = (Level.show_loadingScreen,Level.hide_loadingScreen)
